package org.absolutezero.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Query;
import javax.persistence.Table;
import javax.persistence.Version;

import org.absolutezero.client.util.Session;



@Entity
@Table(name="shelf_user")
public class User implements Serializable{

	private static Logger logger = Logger.getLogger(User.class.getName());

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;
	
	@Version
	private Integer version;
	
	private String login;
	
	private String fullName;
	
	private String password;
	
	@OneToMany(mappedBy="owner",cascade={CascadeType.MERGE})
	private List<Shelf> shelves = new ArrayList<Shelf>();
	
	@OneToMany(mappedBy="author",cascade={CascadeType.MERGE})
	private List<Recipe> recipes = new ArrayList<Recipe>();
	
	public List<Shelf> getShelves(){
		return shelves;
	}
	
	public void setShelves(List<Shelf> shelves){
		this.shelves = shelves;
	}
	
	public Integer getVersion(){
		return version;
	}
	
	public void setVersion(Integer version){
		this.version = version;
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}
	

	public String getLogin() {
		return login;
	}

	public void setLogin(String login) {
		this.login = login;
	}

	public String getFullName() {
		return fullName;
	}

	public void setFullName(String fullName) {
		this.fullName = fullName;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}
	
	 public void persist() {
		 logger.info("Persisting user");
		 logger.info(toString());
 	    EntityManager em = entityManager();
 	    try {
 	      EntityTransaction tx  = em.getTransaction();
 	      tx.begin();
 	      em.persist(this);
 	      tx.commit();
 	    }
 	    
 	    finally {
 	      em.close();
 	     logger.info("EM close");
 	    }
 	}
	 
    public static User login(String name, String password){
    	logger.info(String.format("Checking user is in database: [%s, %s]",name, password));
    	
    	EntityManager em = entityManager();
    	Query q = em.createQuery("SELECT u FROM User u WHERE u.login = :login AND u.password = :password");
    	q.setParameter("login", name);
    	q.setParameter("password", password);
    	
    	List<User> users = (List<User>)q.getResultList();
    	
    	if(users.size() == 0){
    		return null;
    	}
    	else{
    		return users.get(0);
    	}
    	
    }
    
    public static void logout(){
    	Session.clear();
    }

 	public void remove() {
 	    EntityManager em = entityManager();
 	    try {
 	      User attached = em.find(User.class, this.id);
 	      em.remove(attached);
 	    } finally {
 	      em.close();
 	    }
    }
 	
 	private static EntityManager entityManager(){
 		return EMF.get().createEntityManager();
 	}
 	
 	
 	public static User findUser(Long id){
 		logger.info("find user");
 		if (id == null) {
 		      return null;
	    }
	    EntityManager em = entityManager();
	    try {
	      User user = em.find(User.class, id);
	      return user;
	    } finally {
	      em.close();
	    }
 	}
 	
 	public static User find(Integer id){
 		logger.info("find user");
 		if (id == null) {
 		      return null;
	    }
	    EntityManager em = entityManager();
	    try {
	      User user = em.find(User.class, id);
	      return user;
	    } finally {
	      em.close();
	    }
 	}
 	
 	public void addShelf(Shelf shelf){
 		logger.info("add shelf");
 		
	    EntityManager em = entityManager();
	    try {
	      EntityTransaction tx = em.getTransaction();
	      tx.begin();
	      User user = em.merge(this);
	      List<Shelf> sh = user.getShelves();
	      sh.add(shelf);
	      user.setShelves(sh);
	      tx.commit();
	     
	    } finally {
	      em.close();
	    }
 	}
 	
 	public void updateShelf(Shelf shelf){
 		logger.info("update shelf");
 		
	    EntityManager em = entityManager();
	    try {
	      EntityTransaction tx = em.getTransaction();
	      tx.begin();
	      User user = em.merge(this);
	      List<Shelf> sh = user.getShelves();
	      int ind = sh.indexOf(shelf);
	      sh.remove(ind);
	      sh.add(ind, shelf);
	      user.setShelves(sh);
	      tx.commit();
	     
	    } finally {
	      em.close();
	    }
 	}
 	
 	public List<Shelf> fetchShelves(){
 		logger.info("fetch shelves");
 		
	    EntityManager em = entityManager();
	    try {
	      User user = em.merge(this);
	      Query q = em.createQuery("SELECT s FROM Shelf s WHERE s.owner.id = :id");
	      q.setParameter("id", user.getId());
	      return q.getResultList();
	     
	    } finally {
	      em.close();
	    }
 	}
 	
 	@Override
 	public String toString(){
 		return String.format("User[%d, %s, %s, %s]", id, login, fullName, password);
 	}
 	
 	
}
